Control Flow এবং Branching (Control Flow and Branching)

Computer Programming - অ্যাসেম্বলি প্রোগ্রামিং (Assembly Programming)
252
252

Control Flow এবং Branching হল Assembly Language প্রোগ্রামিংয়ের গুরুত্বপূর্ণ ধারণা, যা প্রোগ্রামের কার্যপ্রণালী নিয়ন্ত্রণ করতে এবং শর্তের ভিত্তিতে বিভিন্ন কোড ব্লকে গমন করতে সহায়তা করে। এগুলি CPU-র কার্যপ্রণালী এবং প্রোগ্রামের লজিক্যাল স্ট্রাকচার তৈরি করতে ব্যবহৃত হয়।


Control Flow:
Control Flow নির্দেশ করে যে প্রোগ্রামটি কোন ক্রমে পরিচালিত হবে এবং এটি বিভিন্ন নির্দেশনার মধ্যে গমন করে। Control Flow নির্দেশনাগুলি CPU-কে নির্দেশ দেয় কোন ধরণের অপারেশন করতে হবে এবং কখন কোন অংশে যেতে হবে।

  1. Sequential Control Flow:
    • সাধারণত, Assembly কোডে নির্দেশনাগুলি লাইন দ্বারা লাইন সম্পন্ন হয়, যা Sequential Control Flow হিসেবে পরিচিত।
    • উদাহরণ:

      MOV AX, 5       ; AX-এ ৫ লোড করা
      ADD AX, 3       ; AX-এ ৩ যোগ করা
  2. Conditional Control Flow:
    • শর্তাধীন অবস্থায় Control Flow নির্দেশ করে যে কোন নির্দেশনা চালানো হবে। এটি সাধারণত শর্তাধীন Branching নির্দেশনার মাধ্যমে সম্পন্ন হয়।

Branching:
Branching হল Control Flow-এর একটি অংশ, যা প্রোগ্রামটি শর্তের ভিত্তিতে বিভিন্ন নির্দেশনার মধ্যে যেতে সহায়তা করে। বিভিন্ন Branching নির্দেশনা রয়েছে, যা CPU-কে শর্তের ভিত্তিতে নির্দেশনা কার্যকর করতে সক্ষম করে।

  1. JMP (Jump):
    • সংজ্ঞা: JMP নির্দেশনা একটি নির্দিষ্ট ঠিকানায় অগ্রসর হয়, এটি প্রোগ্রামের প্রবাহ পরিবর্তন করে।
    • উদাহরণ:

      JMP label_name  ; label_name এ গমন
  2. Conditional Jumps:
    • শর্ত অনুযায়ী গমন করা হয়। কিছু সাধারণ Conditional Jump নির্দেশনা:
      • JE (Jump if Equal): যদি পূর্ববর্তী তুলনায় সমান হয়।
      • JNE (Jump if Not Equal): যদি পূর্ববর্তী তুলনায় সমান না হয়।
      • JG (Jump if Greater): যদি পূর্ববর্তী তুলনার ফলাফল বড় হয়।
      • JL (Jump if Less): যদি পূর্ববর্তী তুলনার ফলাফল ছোট হয়।
    • উদাহরণ:

      CMP AX, BX      ; AX এবং BX তুলনা করা
      JE equal_label   ; সমান হলে equal_label এ গমন
      JNE not_equal    ; সমান না হলে not_equal এ গমন
  3. CALL এবং RET:
    • CALL: ফাংশন বা সাবরুটিন কল করার জন্য ব্যবহৃত হয় এবং বর্তমান অবস্থানকে স্ট্যাকে সংরক্ষণ করে।
    • RET: ফাংশন থেকে ফিরে আসার জন্য ব্যবহৃত হয়, যা পূর্ববর্তী অবস্থানে ফিরে যায়।
    • উদাহরণ:

      CALL myFunction  ; myFunction কল করা
      ...
      myFunction:      ; ফাংশনের শুরু
      RET              ; ফাংশন থেকে ফিরে আসা

সারসংক্ষেপ

Control Flow এবং Branching Assembly Language প্রোগ্রামিংয়ে গুরুত্বপূর্ণ অংশ, যা প্রোগ্রামের কার্যপ্রণালী এবং শর্ত অনুযায়ী নির্দেশনা পরিবর্তনের জন্য ব্যবহৃত হয়। Control Flow নির্দেশ করে কোডের ক্রমবদ্ধ কার্যক্রম, যখন Branching শর্তের ভিত্তিতে বিভিন্ন অংশে যাওয়ার জন্য নির্দেশনা সরবরাহ করে। JMP, Conditional Jumps, CALL, এবং RET নির্দেশনাগুলি এই প্রক্রিয়াকে পরিচালনা করতে সাহায্য করে।

common.content_added_by

JMP Instruction এবং Unconditional Branching

251
251

JMP Instruction হলো Assembly Language-এর একটি গুরুত্বপূর্ণ নির্দেশনা, যা প্রোগ্রাম কাউন্টার (Instruction Pointer) সরাসরি নির্দিষ্ট ঠিকানায় স্থানান্তরিত করে। এটি প্রোগ্রাম প্রবাহে পরিবর্তন আনার জন্য ব্যবহৃত হয় এবং Unconditional Branching নির্দেশনা হিসেবে পরিচিত, কারণ এটি শর্তহীনভাবে কাজ করে।


JMP Instruction এর গঠন:
JMP Instruction-এর সাধারণ গঠন নিম্নরূপ:

JMP label
  • label: প্রোগ্রামে সেই নির্দিষ্ট স্থানের নাম যেখানে JMP নির্দেশনা যাওয়ার নির্দেশ দেয়।

JMP Instruction এর ব্যবহার:
JMP Instruction-এর মাধ্যমে প্রোগ্রাম প্রবাহ একটি নির্দিষ্ট অংশে স্থানান্তরিত হয়, যা লুপ তৈরি, ফাংশন কল বা অন্যান্য নির্দিষ্ট অপারেশন সম্পাদনে সহায়ক।

উদাহরণ:

start:
    MOV AX, 5       ; AX রেজিস্টারে ৫ লোড করা
    ADD AX, 2       ; AX-এ ২ যোগ করা
    JMP end_label   ; প্রোগ্রাম প্রবাহ 'end_label' এ চলে যাবে

middle:
    SUB AX, 1       ; এই অংশটি JMP এর কারণে কার্যকর হবে না

end_label:
    MOV BX, AX      ; BX রেজিস্টারে AX এর মান স্থানান্তর

ব্যাখ্যা:

  • JMP end_label নির্দেশনাটি কার্যকর হলে, প্রোগ্রাম সরাসরি end_label এ চলে যায় এবং middle অংশটি কার্যকর হয় না।

Unconditional Branching এর সুবিধা এবং সীমাবদ্ধতা

সুবিধা:

  • প্রোগ্রাম প্রবাহ নিয়ন্ত্রণ: JMP Instruction দিয়ে প্রোগ্রামের প্রবাহকে ইচ্ছেমতো নিয়ন্ত্রণ করা যায়, যা লুপ বা শর্তহীন কাজের জন্য কার্যকর।
  • সহজ লজিকাল ফ্লো: নির্দিষ্ট লজিকাল প্রবাহ তৈরি করতে সহজ।
  • ইনফিনিট লুপ: JMP Instruction ব্যবহার করে প্রোগ্রামে ইনফিনিট লুপ তৈরি করা সম্ভব।

সীমাবদ্ধতা:

  • শর্তহীন প্রবাহ: JMP Instruction সবসময় শর্তহীনভাবে কাজ করে, তাই এটি সহজে ভুল এবং অনিচ্ছাকৃত লজিক্যাল সমস্যা সৃষ্টি করতে পারে।
  • কোড পাঠযোগ্যতা: প্রোগ্রাম প্রবাহে অতিরিক্ত JMP ব্যবহার কোডকে জটিল এবং কঠিন করে তোলে।
  • ডিবাগিং সমস্যা: অতিরিক্ত এবং অপ্রয়োজনীয় JMP ব্যবহার প্রোগ্রামের ডিবাগিং এবং রক্ষণাবেক্ষণ কঠিন করতে পারে।

ব্যবহারিক উদাহরণ: লুপ তৈরি

JMP Instruction ব্যবহার করে একটি লুপ তৈরি করা সম্ভব:

loop_start:
    MOV CX, 5       ; CX রেজিস্টারে ৫ লোড করা
repeat:
    DEC CX          ; CX এক দ্বারা কমানো
    JNZ repeat      ; যদি CX জিরো না হয়, তবে 'repeat' এ লাফ দেয়
loop_end:

ব্যাখ্যা:

  • এই উদাহরণে, JNZ repeat নির্দেশনাটি শর্তাধীন লাফ নির্দেশনা হলেও, JMP নির্দেশনা ব্যবহার করে প্রোগ্রামের নির্দিষ্ট অংশে নিয়মিতভাবে লাফানো সম্ভব।

সারসংক্ষেপ

JMP Instruction Assembly Language-এ প্রোগ্রামের প্রবাহকে শর্তহীনভাবে পরিবর্তন করতে ব্যবহৃত হয় এবং এটি Unconditional Branching নির্দেশনা হিসেবে কাজ করে। এটি প্রোগ্রামের বিভিন্ন লজিক্যাল কাজের জন্য উপযোগী, যেমন লুপ তৈরি এবং ফাংশন কল। তবে অতিরিক্ত ব্যবহারে প্রোগ্রামের জটিলতা ও ডিবাগিং সমস্যা তৈরি হতে পারে।

common.content_added_by

Conditional Branching Instructions: JE, JNE, JL, JG, JZ, JNZ

229
229

Assembly Language-এ Conditional Branching Instructions প্রোগ্রামের নিয়ন্ত্রণ প্রবাহ পরিবর্তনের জন্য ব্যবহৃত হয়। এগুলি সাধারণত CPU-এর ফ্ল্যাগ রেজিস্টারের ভিত্তিতে কাজ করে এবং শর্ত পূরণ হলে নির্দিষ্ট ঠিকানায় লাফ দেয়।


JE (Jump if Equal):

  • সংজ্ঞা: JE নির্দেশনা ZF (Zero Flag) সেট থাকলে জাম্প করে, অর্থাৎ যখন দুটি অপারেন্ড সমান হয়।
  • ব্যবহার:

    CMP AX, BX     ; AX এবং BX তুলনা
    JE label       ; যদি AX == BX হয়, তাহলে label এ জাম্প

JNE (Jump if Not Equal):

  • সংজ্ঞা: JNE নির্দেশনা ZF রিসেট (সেট নয়) থাকলে জাম্প করে, অর্থাৎ যখন দুটি অপারেন্ড সমান নয়।
  • ব্যবহার:

    CMP AX, BX     ; AX এবং BX তুলনা
    JNE label      ; যদি AX != BX হয়, তাহলে label এ জাম্প

JL (Jump if Less):

  • সংজ্ঞা: JL নির্দেশনা SF (Sign Flag) এবং OF (Overflow Flag) যাচাই করে জাম্প করে। এটি signed সংখ্যার ক্ষেত্রে ব্যবহৃত হয় যখন প্রথম অপারেন্ড দ্বিতীয় অপারেন্ডের চেয়ে ছোট।
  • ব্যবহার:

    CMP AX, BX     ; AX এবং BX তুলনা
    JL label       ; যদি AX < BX হয় (signed), তাহলে label এ জাম্প

JG (Jump if Greater):

  • সংজ্ঞা: JG নির্দেশনা ZF রিসেট এবং SF ও OF সমান থাকলে জাম্প করে। এটি signed সংখ্যার ক্ষেত্রে ব্যবহৃত হয় যখন প্রথম অপারেন্ড দ্বিতীয় অপারেন্ডের চেয়ে বড়।
  • ব্যবহার:

    CMP AX, BX     ; AX এবং BX তুলনা
    JG label       ; যদি AX > BX হয় (signed), তাহলে label এ জাম্প

JZ (Jump if Zero):

  • সংজ্ঞা: JZ নির্দেশনা ZF (Zero Flag) সেট থাকলে জাম্প করে। এটি সাধারণত অপারেশন বা তুলনার ফলাফল শূন্য হলে ব্যবহৃত হয়। এটি JE নির্দেশনার সমার্থক।
  • ব্যবহার:

    CMP AX, 0      ; AX এবং 0 তুলনা
    JZ label       ; যদি AX == 0 হয়, তাহলে label এ জাম্প

JNZ (Jump if Not Zero):

  • সংজ্ঞা: JNZ নির্দেশনা ZF রিসেট থাকলে জাম্প করে। এটি সাধারণত অপারেশন বা তুলনার ফলাফল শূন্য না হলে ব্যবহৃত হয়। এটি JNE নির্দেশনার সমার্থক।
  • ব্যবহার:

    CMP AX, 0      ; AX এবং 0 তুলনা
    JNZ label      ; যদি AX != 0 হয়, তাহলে label এ জাম্প

উদাহরণ: Conditional Branching ব্যবহার করে Assembly প্রোগ্রাম

section .text
    global _start

_start:
    MOV AX, 10        ; AX রেজিস্টারে 10 লোড
    MOV BX, 5         ; BX রেজিস্টারে 5 লোড
    CMP AX, BX        ; AX এবং BX তুলনা

    JE equal_label    ; যদি AX == BX হয়, তাহলে equal_label এ জাম্প
    JG greater_label  ; যদি AX > BX হয়, তাহলে greater_label এ জাম্প
    JL less_label     ; যদি AX < BX হয়, তাহলে less_label এ জাম্প

equal_label:
    ; এখানে AX এবং BX সমান হলে কার্যকর হবে
    ; কোড ব্লক
    JMP end           ; প্রোগ্রামের শেষ

greater_label:
    ; এখানে AX > BX হলে কার্যকর হবে
    ; কোড ব্লক
    JMP end           ; প্রোগ্রামের শেষ

less_label:
    ; এখানে AX < BX হলে কার্যকর হবে
    ; কোড ব্লক
    JMP end           ; প্রোগ্রামের শেষ

end:
    ; প্রোগ্রাম শেষ

সারসংক্ষেপ

JE, JNE, JL, JG, JZ, এবং JNZ নির্দেশনাগুলি Assembly Language-এ শর্তমূলক ব্রাঞ্চিং নিশ্চিত করতে ব্যবহৃত হয়। এগুলি প্রোগ্রামের নিয়ন্ত্রণ প্রবাহ পরিবর্তন করে এবং CPU-এর ফ্ল্যাগ রেজিস্টারের ভিত্তিতে কাজ করে। JE এবং JZ সাধারণত সমতুল্য, এবং JNE এবং JNZ একে অপরের সমার্থক। এগুলি প্রোগ্রামের কার্যপ্রণালীতে শর্তমূলক সিদ্ধান্ত গ্রহণে গুরুত্বপূর্ণ ভূমিকা পালন করে।

common.content_added_by

LOOP Instruction এবং তার ব্যবহার

217
217

LOOP Instruction হলো Assembly Language-এ ব্যবহৃত একটি কন্ট্রোল ফ্লো নির্দেশনা যা লুপ স্ট্রাকচার তৈরি করতে সাহায্য করে। এটি নির্দিষ্ট সংখ্যক বার একটি কোড ব্লক পুনরায় কার্যকর করতে ব্যবহৃত হয়।


LOOP Instruction এর গঠন:

LOOP label
  • label: কোডের সেই অংশ নির্দেশ করে যেখানে লুপটি পুনরায় শুরু হবে।

LOOP Instruction-এর কাজের প্রক্রিয়া:

  1. CX রেজিস্টার: LOOP Instruction এর সাথে কাজ করার জন্য CX রেজিস্টারের মান ব্যবহার করা হয়। লুপ শুরু হওয়ার সময় CX রেজিস্টারে ইন্টারেশন সংখ্যাটি লোড করা হয়।
  2. ডিক্রিমেন্ট এবং চেক: প্রতিবার LOOP Instruction কার্যকর হওয়ার পর CX রেজিস্টারের মান ১ কমে যায়।
  3. কন্ডিশন চেক: CX রেজিস্টারের মান 0 না হলে লুপটি লেবেলে নির্দেশিত স্থানে ফিরে যায় এবং কোড পুনরায় কার্যকর হয়। CX যখন 0 হয়ে যায়, লুপটি থেমে যায় এবং লুপের পরবর্তী কোড কার্যকর হয়।

LOOP Instruction এর উদাহরণ:
নিচে একটি উদাহরণ দেওয়া হলো যেখানে একটি লুপ ব্যবহার করে একটি সংখ্যাকে ৫ বার প্রিন্ট করা হচ্ছে:

MOV CX, 5        ; CX রেজিস্টারে ৫ লোড করা (লুপের ইন্টারেশন সংখ্যা)
start_loop:
    ; এখানে যে কোডটি লুপের ভিতরে কার্যকর করা হবে তা লিখুন
    MOV AH, 2    ; DOS interrupt জন্য AH রেজিস্টার সেট করা
    MOV DL, 'A'  ; প্রিন্ট করার জন্য DL রেজিস্টারে ক্যারেক্টার লোড করা
    INT 21h      ; DOS interrupt কল করা (প্রিন্ট)

    LOOP start_loop ; CX ডিক্রিমেন্ট করে এবং যদি CX ≠ 0 হয়, তাহলে লেবেলে ফিরে যায়

LOOP Instruction এর ব্যবহার:

  • ইন্টারেশন: কোনো একটি কাজ নির্দিষ্ট সংখ্যক বার সম্পন্ন করার জন্য ব্যবহৃত হয়, যেমন: অ্যারে ট্রাভার্সাল, সংখ্যা প্রিন্টিং ইত্যাদি।
  • সাধারণ লুপ: সি-ল্যাঙ্গুয়েজের for বা while লুপের মতোই ব্যবহার করা যায়।
  • সহজ ব্যবহার: এটি ব্যবহার করা সহজ কারণ সরাসরি CX রেজিস্টারের ওপর নির্ভর করে লুপের ইন্টারেশন সংখ্যা নিয়ন্ত্রণ করা যায়।

LOOP Instruction এর সীমাবদ্ধতা:

  • কেবলমাত্র CX রেজিস্টার: এটি শুধুমাত্র CX রেজিস্টারের উপর নির্ভর করে কাজ করে। অন্যান্য রেজিস্টার ব্যবহার করে লুপ পরিচালনা করা হলে JMP বা JNZ এর মতো নির্দেশনা ব্যবহার করতে হয়।
  • সীমিত কার্যকারিতা: লজিক্যাল শর্তের উপর ভিত্তি করে লুপ কন্ডিশন পরীক্ষা করার জন্য অতিরিক্ত কোড প্রয়োজন হতে পারে।

সারসংক্ষেপ

LOOP Instruction Assembly Language প্রোগ্রামিংয়ে সহজেই লুপ তৈরি করতে ব্যবহৃত হয়, যা CX রেজিস্টারের উপর ভিত্তি করে নির্দিষ্ট সংখ্যক বার কোড ব্লক কার্যকর করে। এটি ইন্টারেশন সহজে পরিচালনা করতে সাহায্য করে, তবে জটিল লুপ লজিকের জন্য অতিরিক্ত নির্দেশনা প্রয়োজন হতে পারে।

common.content_added_by

Call এবং Return Instructions এর মাধ্যমে Subroutine Call

221
221

Arithmetic Overflow এবং Carry Flag Assembly Language প্রোগ্রামিংয়ে দুটি গুরুত্বপূর্ণ ধারণা, যা CPU-এর অপারেশনগুলির ফলাফল সম্পর্কে বিস্তারিত তথ্য প্রদান করে। Overflow এবং Carry ফ্ল্যাগগুলি সাধারণত অ্যারিথমেটিক অপারেশনগুলির সময় ব্যবহৃত হয় এবং বিভিন্ন ধরণের গাণিতিক ফলাফল বুঝতে সাহায্য করে।


Arithmetic Overflow

  • সংজ্ঞা: Arithmetic Overflow ঘটে যখন একটি গাণিতিক অপারেশনের ফলাফল CPU-র নির্দিষ্ট রেজিস্টারের আকারকে ছাড়িয়ে যায়। উদাহরণস্বরূপ, একটি ৮-বিট রেজিস্টারে (+127) এর বেশি বা (-128) এর কম মান হলে Overflow ঘটে।
  • Overflow Flag (OF):
    • বর্ণনা: OF ফ্ল্যাগটি CPU-র EFLAGS রেজিস্টারে থাকে এবং এটি অ্যারিথমেটিক অপারেশনের সময় Overflow ঘটলে সেট (1) হয়।
    • ব্যবহার: প্রোগ্রামে শর্তানুসারে Overflow ঘটেছে কি না তা চেক করতে ব্যবহৃত হয়।
  • উদাহরণ:

    MOV AL, 127      ; AL রেজিস্টারে 127 লোড করা
    ADD AL, 1        ; AL-এ 1 যোগ করা, ফলে Overflow ঘটে (AL এর মান -128)
    ; এখানে Overflow Flag সেট হবে

নোট: Overflow সাধারণত Signed সংখ্যার ক্ষেত্রে ব্যবহৃত হয়, যেখানে Signed বাইনারি যোগ বা বিয়োগের সময় এটি ঘটে।


Carry Flag Management

  • সংজ্ঞা: Carry Flag ব্যবহৃত হয় Unsigned সংখ্যার অ্যারিথমেটিক অপারেশনে, যখন একটি অপারেশনের ফলে অতিরিক্ত ১ বা ক্যারি তৈরি হয়। এটি নির্দেশ করে যে ফলাফলটি রেজিস্টারের আকার ছাড়িয়ে গেছে।
  • Carry Flag (CF):
    • বর্ণনা: CF ফ্ল্যাগ CPU-র EFLAGS রেজিস্টারে থাকে এবং এটি ক্যারি বা ঋণ (borrow) হলে সেট (1) হয়।
    • ব্যবহার: Unsigned যোগ এবং বিয়োগ অপারেশনের সময় ক্যারি চেক করতে ব্যবহৃত হয়।
  • উদাহরণ:

    MOV AL, 255      ; AL রেজিস্টারে 255 লোড করা
    ADD AL, 1        ; AL-এ 1 যোগ করা, ফলে Carry Flag সেট হবে (AL এর মান 0)
    ; এখানে Carry Flag সেট হবে

নোট: Carry Flag সাধারণত Unsigned সংখ্যার ক্ষেত্রে ব্যবহৃত হয়, যেখানে Unsigned বাইনারি যোগ বা বিয়োগের সময় এটি গুরুত্বপূর্ণ।


Overflow এবং Carry Flag এর মধ্যে পার্থক্য

ফ্ল্যাগব্যবহারযখন সেট হয়
Overflow Flag (OF)Signed সংখ্যার অপারেশনেযখন ফলাফল রেজিস্টারের সীমা ছাড়িয়ে যায় এবং Signed সংখ্যা হিসেবে ভুল ফলাফল দেয়।
Carry Flag (CF)Unsigned সংখ্যার অপারেশনেযখন অপারেশনের ফলে অতিরিক্ত ক্যারি বা ঋণ (borrow) তৈরি হয়।

ফ্ল্যাগ ম্যানেজমেন্ট কৌশল

  • Carry Flag ম্যানেজমেন্ট:
    • ADC (Add with Carry) এবং SBB (Subtract with Borrow) নির্দেশনা ব্যবহার করে Carry Flag-এর উপর ভিত্তি করে অ্যারিথমেটিক অপারেশন করা যায়।

      MOV AL, 100
      ADD AL, 200      ; AL-এ 200 যোগ করা, ফলে CF সেট হবে কারণ ফলাফল 256
      ADC BL, 0        ; BL-এ 0 যোগ করা, এবং CF যদি সেট থাকে তবে অতিরিক্ত 1 যোগ করা হবে
  • Overflow Flag ম্যানেজমেন্ট:
    • Overflow Flag চেক করার জন্য JO (Jump if Overflow) এবং JNO (Jump if No Overflow) নির্দেশনা ব্যবহার করা হয়।

      ADD AL, BL       ; AL এবং BL যোগ করা
      JO overflow_label ; যদি Overflow ঘটে, তাহলে overflow_label এ জাম্প করা হবে

সারসংক্ষেপ

Arithmetic Overflow এবং Carry Flag Management Assembly Language প্রোগ্রামিংয়ে অপারেশনের ফলাফল সঠিকভাবে বুঝতে এবং পরবর্তী লজিকাল পদক্ষেপ গ্রহণ করতে গুরুত্বপূর্ণ ভূমিকা পালন করে। Overflow Flag Signed অপারেশনের সময় ব্যবহৃত হয় যখন ফলাফল রেজিস্টারের সীমা ছাড়িয়ে যায়, আর Carry Flag Unsigned অপারেশনে অতিরিক্ত ক্যারি নির্দেশ করে। এগুলি ব্যবহার করে CPU-এর অপারেশনগুলির ফলাফল যাচাই ও নিয়ন্ত্রণ করা যায়।

common.content_added_by
টপ রেটেড অ্যাপ

স্যাট অ্যাকাডেমী অ্যাপ

আমাদের অল-ইন-ওয়ান মোবাইল অ্যাপের মাধ্যমে সীমাহীন শেখার সুযোগ উপভোগ করুন।

ভিডিও
লাইভ ক্লাস
এক্সাম
ডাউনলোড করুন
Promotion